/*
 *    Copyright © OpenAtom Foundation.
 *
 *    Licensed under the Apache License, Version 2.0 (the "License");
 *    you may not use this file except in compliance with the License.
 *    You may obtain a copy of the License at
 *
 *         http://www.apache.org/licenses/LICENSE-2.0
 *
 *    Unless required by applicable law or agreed to in writing, software
 *    distributed under the License is distributed on an "AS IS" BASIS,
 *    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *    See the License for the specific language governing permissions and
 *    limitations under the License.
 */

package com.inspur.edp.cef.designtime.api.json.object;

import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.DeserializationContext;
import com.fasterxml.jackson.databind.JsonDeserializer;
import com.inspur.edp.cef.designtime.api.IGspCommonDataType;
import com.inspur.edp.cef.designtime.api.IGspCommonField;
import com.inspur.edp.cef.designtime.api.collection.CommonDtmCollection;
import com.inspur.edp.cef.designtime.api.collection.CommonValCollection;
import com.inspur.edp.cef.designtime.api.collection.GspFieldCollection;
import com.inspur.edp.cef.designtime.api.element.GspAssociation;
import com.inspur.edp.cef.designtime.api.entity.CustomizationInfo;
import com.inspur.edp.cef.designtime.api.entity.GspCommonDataType;
import com.inspur.edp.cef.designtime.api.json.CefNames;
import com.inspur.edp.cef.designtime.api.json.SerializerUtils;
import com.inspur.edp.cef.designtime.api.json.element.CefFieldDeserializer;
import com.inspur.edp.cef.designtime.api.json.operation.CommonDtmDeserializer;
import com.inspur.edp.cef.designtime.api.json.operation.CommonValDeserializer;
import java.io.IOException;
import java.util.ArrayList;

import static com.fasterxml.jackson.core.JsonToken.FIELD_NAME;

/**
 * The Json Parser Of CommonDataType
 *
 * @ClassName: GspCommonDataTypeDeserializer
 * @Author: Benjamin Gong
 * @Date: 2021/1/11 17:13
 * @Version: V1.0
 */
public abstract class GspCommonDataTypeDeserializer extends JsonDeserializer<IGspCommonDataType> {
	private GspCommonDataType commonDataType;

	public String getFlag() {
		return flag;
	}

	public void setFlag(String flag) {
		if(flag == null)
			return;
		this.flag = flag;
	}

	private String flag = "V1";

	protected abstract void beforeCefObjectDeserializer(GspCommonDataType commonDataType);

	@Override
	public IGspCommonDataType deserialize(JsonParser jsonParser, DeserializationContext deserializationContext) throws IOException, JsonProcessingException {
		return deserializeCommonDataType(jsonParser);
	}

	public IGspCommonDataType deserializeCommonDataType(JsonParser jsonParser) {
		commonDataType = createCommonDataType();
        commonDataType.setBeLabel(new ArrayList<>());
        commonDataType.setBizTagIds(new ArrayList<>());
        commonDataType.setIsRef(false);
		beforeCefObjectDeserializer(commonDataType);

		SerializerUtils.readStartObject(jsonParser);
		while (jsonParser.getCurrentToken() == FIELD_NAME) {
			String propName = SerializerUtils.readPropertyName(jsonParser);
			readPropertyValue(commonDataType, propName, jsonParser);
		}
		SerializerUtils.readEndObject(jsonParser);

		afterReadCommonDataType(commonDataType);
		buildI18n(commonDataType);
		return commonDataType;
	}

	//#region 私有方法

	private void readPropertyValue(GspCommonDataType commonDataType, String propName, JsonParser jsonParser) {
		switch (propName) {
			case CefNames.ID:
				commonDataType.setID(SerializerUtils.readPropertyValue_String(jsonParser));
				break;
			case CefNames.Code:
				commonDataType.setCode(SerializerUtils.readPropertyValue_String(jsonParser));
				break;
			case CefNames.Name:
				commonDataType.setName(SerializerUtils.readPropertyValue_String(jsonParser));
				break;
			case CefNames.BeLabel:
				commonDataType.setBeLabel(SerializerUtils.readStringArray(jsonParser));
				break;
			case CefNames.BizTagIds:
				commonDataType.setBizTagIds(SerializerUtils.readStringArray(jsonParser));
				break;
			case CefNames.IsRef:
				commonDataType.setIsRef(SerializerUtils.readPropertyValue_boolean(jsonParser));
				break;
			case CefNames.DtmBeforeSave:
				readDtmBeforeSave(jsonParser, commonDataType);
				break;
			case CefNames.DtmAfterModify:
				readDtmAfterModify(jsonParser, commonDataType);
				break;
			case CefNames.DtmAfterCreate:
				readDtmAfterCreate(jsonParser, commonDataType);
				break;
			case CefNames.ValAfterModify:
				readValAfterModify(jsonParser, commonDataType);
				break;
			case CefNames.ValBeforeSave:
				readValBeforeSave(jsonParser, commonDataType);
				break;
			case CefNames.ContainElements:
				readContainElements(jsonParser, commonDataType);
				break;
			case CefNames.EnableDynamicProp:
				//CommonDataType上动态属性相关-已废弃
				SerializerUtils.readPropertyValue_boolean(jsonParser);
				break;
			case CefNames.DynamicPropRepositoryComp:
				//CommonDataType上动态属性相关-已废弃
				SerializerUtils.readPropertyValue_String(jsonParser);
				break;
			case CefNames.DynamicPropSerializerComps:
				//CommonDataType上动态属性相关-已废弃
				SerializerUtils.readStringArray(jsonParser);
				break;
			case CefNames.I18nResourceInfoPrefix:
				commonDataType.setI18nResourceInfoPrefix(SerializerUtils.readPropertyValue_String(jsonParser));
				break;
			case CefNames.CustomizationInfo:
				commonDataType.setCustomizationInfo(SerializerUtils.readPropertyValue_Object(CustomizationInfo.class,jsonParser));
				try {
					jsonParser.nextToken();
				} catch (IOException e) {
					throw new RuntimeException(String.format("GspCommonDataTypeDeserializer反序列化错误：%1$s", propName));
				}
				break;
			default:
				if (!readExtendDataTypeProperty(commonDataType, propName, jsonParser)) {
					throw new RuntimeException(String.format("GspCommonDataTypeDeserializer未识别的属性名：%1$s", propName));
				}
		}
	}

	public void addDetermination(GspCommonDataType commonDataType, CommonDtmCollection dtms, String triggerType){
	}

	private void readContainElements(JsonParser jsonParser, GspCommonDataType commonDataType) {
		GspFieldCollection collection = createFieldCollection();
		SerializerUtils.readArray(jsonParser, createFieldDeserializer(), collection);
		handleContainElements(collection, commonDataType);
		commonDataType.setContainElements(collection);
	}

	private void handleContainElements(GspFieldCollection collection, GspCommonDataType commonDataType) {
		for (IGspCommonField field : collection) {
			field.setBelongObject(commonDataType);
			if (field.getChildAssociations() != null && field.getChildAssociations().getCount() > 0) {
				for (GspAssociation association : field.getChildAssociations()) {
					if (association.getRefElementCollection() != null) {
						for (IGspCommonField assofield : association.getRefElementCollection()) {
							assofield.setBelongObject(commonDataType);
						}
					}
				}
			}
			if(field.getI18nResourceInfoPrefix()==null||"".equals(field.getI18nResourceInfoPrefix()))
				field.setI18nResourceInfoPrefix(commonDataType.getI18nResourceInfoPrefix()+"."+field.getLabelID());

//			if(field.getChildAssociations() != null && field.getChildAssociations().getCount() > 0) {
//				for (GspAssociation ass : field.getChildAssociations()) {
//					if(ass.getI18nResourceInfoPrefix()==null || "".equals(ass.getI18nResourceInfoPrefix())){
//						if(field.getI18nResourceInfoPrefix()!=null && !"".equals(field.getI18nResourceInfoPrefix())) {
//							ass.setI18nResourceInfoPrefix(field.getI18nResourceInfoPrefix());
//						}
//					}
//					if (ass.getRefElementCollection() != null && ass.getRefElementCollection().getCount() > 0) {
//						for (IGspCommonField assField : ass.getRefElementCollection()) {
//							if (assField!=null && (assField.getI18nResourceInfoPrefix() == null || "".equals(assField.getI18nResourceInfoPrefix()))) {
//								if(ass.getI18nResourceInfoPrefix()!=null && !"".equals(ass.getI18nResourceInfoPrefix())) {
//									assField.setI18nResourceInfoPrefix(ass.getI18nResourceInfoPrefix() + "." + assField.getLabelID());
//								}
//							}
//						}
//					}
//				}
//			}
		}
	}

	private void buildI18n(GspCommonDataType commonDataType){
		if(commonDataType.getContainElements()==null || commonDataType.getContainElements().size()==0)
			return;
		if(commonDataType.getI18nResourceInfoPrefix()!=null && !"".equals(commonDataType.getI18nResourceInfoPrefix())) {
			buildElementsI18n(commonDataType.getI18nResourceInfoPrefix(), commonDataType.getContainElements());
		}
	}
	private void buildElementsI18n(String parentI18n, GspFieldCollection commonFields){
		for (IGspCommonField field : commonFields){
			if(needHandle(field.getI18nResourceInfoPrefix()))
				field.setI18nResourceInfoPrefix(parentI18n+"."+field.getLabelID());
			if(field.getChildAssociations() ==null || field.getChildAssociations().size()==0)
				continue;
			buildAssI18n(field);
		}
	}
	private void buildAssI18n(IGspCommonField field){
        for(GspAssociation ass : field.getChildAssociations()){
            if(needHandle(ass.getI18nResourceInfoPrefix()))
                ass.setI18nResourceInfoPrefix(field.getI18nResourceInfoPrefix());
            if(ass.getRefElementCollection()==null || ass.getRefElementCollection().size()==0)
                continue;
            if(ass.getI18nResourceInfoPrefix()!=null && !"".equals(ass.getI18nResourceInfoPrefix()))
                buildElementsI18n(ass.getI18nResourceInfoPrefix(),ass.getRefElementCollection());
        }
    }
	private boolean needHandle(String i18n){
		return (i18n==null || "".equals(i18n) || i18n.contains("null."));
	}

	public final CommonDtmCollection readCommonDtmCollection(JsonParser jsonParser) {
		CommonDtmCollection collection = new CommonDtmCollection();
		CommonDtmDeserializer der = getCommonDtmDeserializer();
		SerializerUtils.readArray(jsonParser, der, collection);
		return collection;
	}

	public CommonDtmDeserializer getCommonDtmDeserializer(){
		return new CommonDtmDeserializer();
	}

	public final CommonValCollection readCommonValidationCollection(JsonParser jsonParser) {
		CommonValCollection collection = new CommonValCollection();
		CommonValDeserializer der = getCommonValDeserializer();
		SerializerUtils.readArray(jsonParser, der, collection);
		return collection;
	}

	public CommonValDeserializer getCommonValDeserializer(){
		return new CommonValDeserializer();
	}

	private void readDtmBeforeSave(JsonParser jsonParser, GspCommonDataType commonDataType) {
		commonDataType.setDtmBeforeSave(readCommonDtmCollection(jsonParser));
		addDetermination(commonDataType, commonDataType.getDtmBeforeSave(), "beforeSave");
	}

	private void readDtmAfterModify(JsonParser jsonParser, GspCommonDataType commonDataType) {
		commonDataType.setDtmAfterModify(readCommonDtmCollection(jsonParser));
		addDetermination(commonDataType, commonDataType.getDtmAfterModify(), "afterModify");
	}

	private void readDtmAfterCreate(JsonParser jsonParser, GspCommonDataType commonDataType) {
		commonDataType.setDtmAfterCreate(readCommonDtmCollection(jsonParser));
		addDetermination(commonDataType, commonDataType.getDtmAfterCreate(), "afterCreate");
	}

	private void readValAfterModify(JsonParser jsonParser, GspCommonDataType commonDataType) {
		commonDataType.setValAfterModify(readCommonValidationCollection(jsonParser));
	}

	private void readValBeforeSave(JsonParser jsonParser, GspCommonDataType commonDataType) {
		commonDataType.setValBeforeSave(readCommonValidationCollection(jsonParser));
	}

	//#endregion

	protected GspCommonDataType getGspCommonDataType() {
		return commonDataType;
	}

	protected abstract GspCommonDataType createCommonDataType();

	protected GspFieldCollection createFieldCollection() {
		return new GspFieldCollection();
	}

	protected abstract CefFieldDeserializer createFieldDeserializer();

	protected boolean readExtendDataTypeProperty(GspCommonDataType commonDataType, String propName, JsonParser jsonParser) {
		return false;
	}

	protected void afterReadCommonDataType(GspCommonDataType commonDataType) {
	}

}
